/*!
 * # [89.格雷编码](https://leetcode.cn/problems/gray-code/description/)
 *
 * @lc app=leetcode.cn id=89 lang=rust
 *
 * ## 难度
 * Medium (75.52%)
 * Likes:    633
 * Dislikes: 0
 * Total Accepted:    119.7K
 * Total Submissions: 158.4K
 * Testcase Example:  '2'
 *
 * ## 描述
 *
 * n 位格雷码序列 是一个由 2^n 个整数组成的序列，其中：
 *
 * - 每个整数都在范围 [0, 2^n - 1] 内（含 0 和 2^n - 1）
 * - 第一个整数是 0
 * - 一个整数在序列中出现 不超过一次
 * - 每对 相邻 整数的二进制表示 恰好一位不同 ，且
 * - 第一个 和 最后一个 整数的二进制表示 恰好一位不同
 *
 * 给你一个整数 n ，返回任一有效的 n 位格雷码序列 。
 *
 *
 * ## 示例 1：
 * - 输入：n = 2
 * - 输出：[0,1,3,2]
 * - 解释：
 * [0,1,3,2] 的二进制表示是 [00,01,11,10] 。
 * - 00 和 01 有一位不同
 * - 01 和 11 有一位不同
 * - 11 和 10 有一位不同
 * - 10 和 00 有一位不同
 * [0,2,3,1] 也是一个有效的格雷码序列，其二进制表示是 [00,10,11,01] 。
 * - 00 和 10 有一位不同
 * - 10 和 11 有一位不同
 * - 11 和 01 有一位不同
 * - 01 和 00 有一位不同
 *
 *
 * ## 示例 2：
 * - 输入：n = 1
 * - 输出：[0,1]
 *
 * ## 提示：
 * - 1 <= n <= 16
 *
 */

// @lc code=start
impl Solution {
    /// ## 格雷编码
    /// - 位运算
    /// 1. 格雷码公式:  i xor ( i >> 1)
    /// 2. 对于一个整数i, i+1 导致二进制的变化规律如下:
    ///    a. 最右边连续的1都变为0;
    ///    b. 最右边第一个0变为1;
    ///    c. 其他位保持不变;
    /// 3. 对于 i ^ ( i >> 1 ) , 计算过程如下:
    /// ```text
    /// i        1   0   1   1   1   0  (0   1   1)
    ///          |\  |\  |\  |\  |\  |\  |\  |\  |
    ///          | \ | \ | \ | \ | \ | \ | \ | \ |
    ///          |  \|  \|  \|  \|  \|  \|  \|  \|
    /// i>>1         1   0   1   1   1   0   0   1
    /// i^(i>>1) 1   1   1   0   0   1  [0]   1   0
    /// ```
    /// 4. 当i增加1时, i ^ ( i >> 1 ) 变化如下:
    /// ```text
    /// j=i+1    1   0   1   1   1   0  (1   0   0)
    ///          |\  |\  |\  |\  |\  |\  |\  |\  |
    ///          | \ | \ | \ | \ | \ | \ | \ | \ |
    ///          |  \|  \|  \|  \|  \|  \|  \|  \|
    ///j^(j>>1)  1   1   1   0   0   1  [1]   1   0
    /// ```
    ///
    pub fn gray_code(n: i32) -> Vec<i32> {
        (0..(1 << n)).map(|i| i ^ (i >> 1)).collect()
    }
}
// @lc code=end

struct Solution;

mod tests {
    use super::*;

    fn test() {
        assert_eq!(Solution::gray_code(1), vec![0, 1]);
        assert_eq!(Solution::gray_code(2), vec![0, 1, 3, 2]);
    }
}
